home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK1.toast / Development Kits (Disc 1) / AppleScript / Development Tools / Sample Code / Sample OSA Component / In MPW Pascal / OSASampleComponent.p < prev    next >
Encoding:
Text File  |  1995-11-08  |  28.9 KB  |  801 lines  |  [TEXT/MPS ]

  1. { Copyright © 1992-1993 Apple Computer, Inc. All rights reserved.}
  2.  
  3. { This is a sample program to implement the OSA interface. }
  4. { In this sample program, the source is the same as the internal compiled form. }
  5. { So compile and decompile just consists of copying and rename, and this is very unlike other OSA implementation. }
  6. { However, there is a lot of scripting language which just interprets the source and this sample program can be useful }
  7. {                                                                                                                                                                            }
  8. { Changed  UprString to UpperString to conform to new function names. R.Silva 11/8/95 }
  9. {                                                                                                                                                                            }
  10. UNIT OSASample;
  11.  
  12.   INTERFACE
  13.  
  14.     USES Errors, Notification, Components, Dialogs, Processes, Aliases, AppleEvents, OSA, OSAComp, TextUtils;
  15.  
  16.     FUNCTION Main(VAR params: ComponentParameters;
  17.                   storage: Handle): ComponentResult;
  18.  
  19.   IMPLEMENTATION
  20.  
  21.     CONST
  22.       MaxIDSlot = 100;
  23.       MySignature = 'SMPL';
  24.  
  25.     TYPE
  26.       GlobalsHandle = ^GlobalsPtr;
  27.       GlobalsPtr = ^GlobalsRecord;
  28.       GlobalsRecord = RECORD
  29.                         gSelf: ComponentInstance;
  30.                         errorNumber: OSErr;
  31.                         errorDesc: AEDesc;
  32.                         scriptIDSlot: ARRAY [1..MaxIDSlot] OF AEDesc;
  33.                       END;
  34.  
  35.     PROCEDURE IgnoreOSErr(anErr: OSErr);
  36.       INLINE $548F; { addq #2,sp }
  37.  
  38.     FUNCTION MyClose(globals: GlobalsHandle;
  39.                      self: ComponentInstance): ComponentResult;
  40.       FORWARD;
  41.  
  42.     FUNCTION MyCanDo(void: GlobalsHandle;
  43.                      selector: INTEGER): ComponentResult;
  44.       FORWARD;
  45.  
  46.     FUNCTION DoOSALoad(globals: GlobalsHandle;
  47.                        scriptData: AEDesc;
  48.                        modeFlags: LONGINT;
  49.                        VAR resultingScriptID: OSAID): ComponentResult;
  50.       FORWARD;
  51.  
  52.     FUNCTION DoOSAStore(globals: GlobalsHandle;
  53.                         scriptID: OSAID;
  54.                         desiredType: DescType;
  55.                         modeFlags: LONGINT;
  56.                         VAR resultingScriptData: AEDesc): ComponentResult;
  57.       FORWARD;
  58.  
  59.     FUNCTION DoOSADispose(globals: GlobalsHandle;
  60.                           scriptID: OSAID): ComponentResult;
  61.       FORWARD;
  62.  
  63.     FUNCTION DoOSAScriptError(globals: GlobalsHandle;
  64.                               selector: OSType;
  65.                               desiredType: DescType;
  66.                               VAR resultingErrorDescription: AEDesc): ComponentResult;
  67.       FORWARD;
  68.  
  69.     FUNCTION DoOSAExecute(globals: GlobalsHandle;
  70.                           compiledScriptID: OSAID;
  71.                           contextID: OSAID;
  72.                           modeFlags: LONGINT;
  73.                           VAR resultingScriptValueID: OSAID): ComponentResult;
  74.       FORWARD;
  75.  
  76.     FUNCTION DoOSAScriptingComponentName(globals: GlobalsHandle;
  77.                                          VAR resultingScriptingComponentName: AEDesc): OSAError;
  78.       FORWARD;
  79.  
  80.     FUNCTION DoOSACompile(globals: GlobalsHandle;
  81.                           sourceData: AEDesc;
  82.                           modeFlags: LONGINT;
  83.                           VAR resultingCompiledScriptID: OSAID): ComponentResult;
  84.       FORWARD;
  85.  
  86.     FUNCTION DoOSAGetSource(globals: GlobalsHandle;
  87.                             scriptID: OSAID;
  88.                             desiredType: DescType;
  89.                             VAR resultingSourceData: AEDesc): ComponentResult;
  90.       FORWARD;
  91.  
  92.     FUNCTION DoOSACoerceFromDesc(globals: GlobalsHandle;
  93.                                  scriptData: AEDesc;
  94.                                  modeFlags: LONGINT;
  95.                                  VAR resultingScriptValueID: OSAID): ComponentResult;
  96.       FORWARD;
  97.  
  98.     FUNCTION DoOSACoerceToDesc(globals: GlobalsHandle;
  99.                                scriptValueID: OSAID;
  100.                                desiredType: DescType;
  101.                                modeFlags: LONGINT;
  102.                                VAR result: AEDesc): ComponentResult;
  103.       FORWARD;
  104.  
  105.     FUNCTION DoOSALoadExecute(globals: GlobalsHandle;
  106.                               scriptData: AEDesc;
  107.                               contextID: OSAID;
  108.                               modeFlags: LONGINT;
  109.                               VAR resultingScriptValueID: OSAID): ComponentResult;
  110.       FORWARD;
  111.  
  112.     FUNCTION DoOSACompileExecute(globals: GlobalsHandle;
  113.                                  sourceData: AEDesc;
  114.                                  contextID: OSAID;
  115.                                  modeFlags: LONGINT;
  116.                                  VAR resultingScriptValueID: OSAID): ComponentResult;
  117.       FORWARD;
  118.  
  119.     FUNCTION DoOSADoScript(globals: GlobalsHandle;
  120.                            sourceData: AEDesc;
  121.                            contextID: OSAID;
  122.                            desiredType: DescType;
  123.                            modeFlags: LONGINT;
  124.                            VAR resultingText: AEDesc): ComponentResult;
  125.       FORWARD;
  126.  
  127.     FUNCTION DoOSAMakeContext(contextName: StringPtr;
  128.                               parentContext: OSAID;
  129.                               VAR resultingContextID: OSAID): ComponentResult;
  130.       FORWARD;
  131.  
  132.     FUNCTION DoOSADisplay(globals: GlobalsHandle;
  133.                           scriptValueID: OSAID;
  134.                           desiredType: DescType;
  135.                           modeFlags: LONGINT;
  136.                           VAR resultingText: AEDesc): ComponentResult;
  137.       FORWARD;
  138.  
  139.     FUNCTION Main(VAR params: ComponentParameters;
  140.                   storage: Handle): ComponentResult;
  141.  
  142.       VAR
  143.         globals: GlobalsHandle;
  144.         self: ComponentInstance;
  145.         err: ComponentResult;
  146.         myErrDesc: AEDesc;
  147.  
  148.       BEGIN
  149.         IF params.what < 0 THEN { Negative selectors used for component manager calls }
  150.           CASE (params.what) OF
  151.  
  152.             kComponentOpenSelect:
  153.               BEGIN
  154.               globals := GlobalsHandle(NewHandleClear(sizeof(GlobalsRecord)));
  155.               IF globals = NIL THEN
  156.                 err := MemError
  157.               ELSE
  158.                 BEGIN
  159.                 err := AECreateDesc(typeChar, NIL, 0, myErrDesc);
  160.                 IF err = NoErr THEN
  161.                   BEGIN
  162.                   self := ComponentInstance(params.params[0]);
  163.                   SetComponentInstanceStorage(self, Handle(globals));
  164.                   WITH globals^^ DO
  165.                     BEGIN
  166.                     gSelf := self;
  167.                     errorDesc := myErrDesc;
  168.                     END;
  169.                   END
  170.                 ELSE
  171.                   DisposHandle(Handle(globals));
  172.                 END;
  173.               END;
  174.  
  175.             kComponentCloseSelect: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@MyClose));
  176.  
  177.             kComponentCanDoSelect: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@MyCanDo));
  178.  
  179.             kComponentVersionSelect: err := 0;
  180.  
  181.             OTHERWISE err := badComponentSelector;
  182.           END { Component Manager calls }
  183.  
  184.         ELSE { Specific component routines called through the component manager }
  185.           BEGIN
  186.           CASE (params.what) OF
  187.             kOSASelectLoad: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSALoad));
  188.  
  189.             kOSASelectStore: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSAStore));
  190.  
  191.             kOSASelectExecute: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSAExecute));
  192.  
  193.             kOSASelectDisplay: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSADisplay));
  194.  
  195.             kOSASelectScriptError: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSAScriptError));
  196.  
  197.             kOSASelectDispose: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSADispose));
  198.  
  199.             kOSASelectCompile: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSACompile));
  200.  
  201.             kOSASelectGetSource: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSAGetSource));
  202.  
  203.             kOSASelectScriptingComponentName:
  204.               err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSAScriptingComponentName));
  205.  
  206.             kOSASelectCoerceFromDesc: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSACoerceFromDesc));
  207.  
  208.             kOSASelectCoerceToDesc: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSACoerceToDesc));
  209.  
  210.             kOSASelectLoadExecute: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSALoadExecute));
  211.  
  212.             kOSASelectCompileExecute: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSACompileExecute));
  213.  
  214.             kOSASelectDoScript: err := CallComponentFunctionWithStorage(storage, params, ComponentRoutine(@DoOSADoScript));
  215.  
  216.             kOSASelectMakeContext: err := CallComponentFunction(params, ComponentRoutine(@DoOSAMakeContext));
  217.  
  218.             OTHERWISE
  219.               BEGIN
  220.               err := badComponentSelector;
  221.               END;
  222.           END;
  223.           END;
  224.         Main := err;
  225.       END;
  226.  
  227.     FUNCTION MyClose(globals: GlobalsHandle;
  228.                      self: ComponentInstance): ComponentResult;
  229.  
  230.       VAR
  231.         i: integer;
  232.  
  233.       BEGIN
  234.         HLock(Handle(globals));
  235.         WITH globals^^ DO
  236.           BEGIN
  237.           IgnoreOSErr(AEDisposeDesc(errorDesc));
  238.           FOR i := 1 TO MaxIDSlot DO { dispose all the descriptors in the slots }
  239.             IgnoreOSErr(AEDisposeDesc(scriptIDSlot[i]));
  240.           END;
  241.         HUnLock(Handle(globals));
  242.         MyClose := noErr;
  243.       END;
  244.  
  245.     FUNCTION MyCanDo(void: GlobalsHandle;
  246.                      selector: INTEGER): ComponentResult;
  247.  
  248.       BEGIN
  249.         MyCanDo := 1 { Should have gone through every selector that is supported }
  250.       END;
  251.  
  252.     { utility procedures }
  253.  
  254.     PROCEDURE ClearErrorDesc(globals: GlobalsHandle);
  255.     { clean up the error message }
  256.  
  257.       BEGIN
  258.         WITH globals^^ DO
  259.           BEGIN
  260.           errorNumber := NoErr;
  261.           SetHandleSize(errorDesc.dataHandle, 0);
  262.           END;
  263.       END;
  264.  
  265.     FUNCTION TryDoScript(globals: GlobalsHandle;
  266.                          scriptData: AEDesc;
  267.                          VAR num: Integer): ComponentResult;
  268.     { try to compile the text and return the result }
  269.     { we just try to translate one, two, three etc into number in this simple example }
  270.  
  271.       VAR
  272.         aStr: Str255;
  273.         err: OSErr;
  274.  
  275.       BEGIN
  276.         num := 0;
  277.         IF scriptData.descriptorType = MySignature THEN
  278.           BEGIN
  279.           GetIText(scriptData.dataHandle, aStr);
  280.           UpperString(aStr, false);
  281.           IF aStr = 'ONE' THEN
  282.             num := 1
  283.           ELSE IF aStr = 'TWO' THEN
  284.             num := 2
  285.           ELSE IF aStr = 'THREE' THEN
  286.             num := 3
  287.           ELSE IF aStr = 'FOUR' THEN
  288.             num := 4
  289.           ELSE IF aStr = 'FIVE' THEN
  290.             num := 5
  291.           ELSE IF aStr = 'SIX' THEN
  292.             num := 6
  293.           ELSE IF aStr = 'SEVEN' THEN
  294.             num := 7
  295.           ELSE IF aStr = 'EIGHT' THEN
  296.             num := 8
  297.           ELSE IF aStr = 'NINE' THEN
  298.             num := 9
  299.           ELSE IF aStr = 'TEN' THEN num := 10;
  300.           ClearErrorDesc(globals);
  301.           IF num = 0 THEN
  302.             BEGIN
  303.             err := errOSAScriptError;
  304.             aStr := Concat('Cannot understand ', aStr);
  305.             WITH globals^^ DO
  306.               BEGIN
  307.               errorNumber := err;
  308.               IgnoreOSErr(PtrToXHand(@aStr[1], errorDesc.dataHandle, length(aStr)));
  309.               END;
  310.             END
  311.           ELSE
  312.             err := 0;
  313.           END
  314.         ELSE
  315.           err := errOSABadStorageType;
  316.         TryDoScript := err;
  317.       END;
  318.  
  319.     FUNCTION ActualDoScript(globals: GlobalsHandle;
  320.                             scriptData: AEDesc;
  321.                             VAR result: AEDesc): ComponentResult;
  322.     { execute the script and return a number or set the error result }
  323.  
  324.       VAR
  325.         num: integer;
  326.         err: OSErr;
  327.  
  328.       BEGIN
  329.         err := TryDoScript(globals, scriptData, num);
  330.         IF err = NoErr THEN err := AECreateDesc(typeShortInteger, @num, SizeOf(Integer), result);
  331.         ActualDoScript := err;
  332.       END;
  333.  
  334.     PROCEDURE NukeIt(VAR theDesc: AEDesc);
  335.     { make a null descriptor }
  336.  
  337.       BEGIN
  338.         WITH theDesc DO
  339.           BEGIN
  340.           descriptorType := typeNull;
  341.           dataHandle := NIL;
  342.           END;
  343.       END;
  344.  
  345.     FUNCTION FindScriptIDSlot(globals: GlobalsHandle): longint;
  346.     { search for a empty slot and return the slot ID, return 0 if none is available }
  347.  
  348.       VAR
  349.         i: integer;
  350.  
  351.       BEGIN
  352.         FindScriptIDSlot := 0;
  353.         WITH globals^^ DO
  354.           FOR i := 1 TO MaxIDSlot DO
  355.             IF scriptIDSlot[i].dataHandle = NIL THEN
  356.               BEGIN
  357.               FindScriptIDSlot := i;
  358.               LEAVE;
  359.               END;
  360.       END;
  361.  
  362.     FUNCTION FindSlotAndPutIt(globals: GlobalsHandle;
  363.                               theDesc: AEDesc;
  364.                               VAR slotID: longint): ComponentResult;
  365.     { put a desc into a slot, if slotID starts as 0 find a new slot, otherwise reuse the slot ID }
  366.  
  367.       VAR
  368.         err: OSErr;
  369.         oldDesc: AEDesc;
  370.  
  371.       BEGIN
  372.         IF theDesc.dataHandle = NIL THEN
  373.           BEGIN { we don't have a descriptor, return 0 }
  374.           slotID := 0;
  375.           err := memFullErr;
  376.           END
  377.         ELSE
  378.           BEGIN
  379.           IF slotID = 0 THEN
  380.             slotID := FindScriptIDSlot(globals) { find an empty slot }
  381.           ELSE
  382.             BEGIN { reuse an existing slot, we first dispose the old content }
  383.             oldDesc := globals^^.ScriptIDSlot[slotID];
  384.             IgnoreOSErr(AEDisposeDesc(oldDesc));
  385.             END;
  386.           IF slotID <> 0 THEN
  387.             BEGIN { now we put the descriptor inot the slot }
  388.             globals^^.ScriptIDSlot[slotID] := theDesc;
  389.             err := NoErr;
  390.             END
  391.           ELSE
  392.             BEGIN
  393.             err := memFullErr; { no slot available, treat it as memory error because in a more realistic program we would expand the slot s }
  394.             slotID := 0;
  395.             IgnoreOSErr(AEDisposeDesc(theDesc));
  396.             END;
  397.           END;
  398.         FindSlotAndPutIt := err;
  399.       END;
  400.  
  401.     FUNCTION TextToStxt(textDesc: AEDesc;
  402.                         VAR result: AEDesc): OSErr;
  403.     { convert TEXT to styled text }
  404.  
  405.       TYPE
  406.         myStyleRec = RECORD
  407.                        scrpNStyles: integer;
  408.                        scrpStyle: ScrpSTElement;
  409.                      END;
  410.  
  411.       VAR
  412.         err: OSErr;
  413.         theRec: AERecord;
  414.         myStyle: myStyleRec;
  415.  
  416.       BEGIN
  417.         result.dataHandle := NIL;
  418.         myStyle.scrpNStyles := 1;
  419.         WITH myStyle.scrpStyle DO
  420.           BEGIN
  421.           scrpStartChar := 0;
  422.           scrpHeight := 16;
  423.           scrpAscent := 12;
  424.           scrpFont := 1;
  425.           scrpFace := [bold];
  426.           scrpSize := 12;
  427.           scrpColor.red := 0;
  428.           scrpColor.green := 0;
  429.           scrpColor.blue := 0;
  430.           END;
  431.         err := AECreateList(NIL, 0, true, theRec);
  432.         IF err = NoErr THEN
  433.           BEGIN
  434.           err := AEPutKeyPtr(theRec, 'ksty', 'styl', @myStyle, SizeOf(myStyle));
  435.           IF err = NoErr THEN err := AEPutKeyDesc(theRec, 'ktxt', textDesc);
  436.           IF err = NoErr THEN
  437.             BEGIN
  438.             err := AECoerceDesc(theRec, 'STXT', result);
  439.             IgnoreOSErr(AEDisposeDesc(theRec));
  440.             END
  441.           ELSE
  442.             IgnoreOSErr(AEDisposeDesc(theRec));
  443.           END;
  444.         TextToStxt := err;
  445.       END;
  446.  
  447.     { the OSA component procedures }
  448.  
  449.     FUNCTION DoOSALoad(globals: GlobalsHandle;
  450.                        scriptData: AEDesc;
  451.                        modeFlags: LONGINT;
  452.                        VAR resultingScriptID: OSAID): ComponentResult;
  453.     { make a copy, strip the trailer and put it into a slot }
  454.  
  455.       VAR
  456.         err: ComponentResult;
  457.         descCopy: AEDesc;
  458.         itsType: DescType;
  459.  
  460.       BEGIN
  461.         err := errOSABadStorageType;
  462.         IF (scriptData.descriptorType = kOSAGenericScriptingComponentSubtype) THEN
  463.           IF OSAGetStorageType(scriptData.dataHandle, itsType) = NoErr THEN
  464.             IF itsType = MySignature THEN
  465.               BEGIN
  466.               err := AEDuplicateDesc(scriptData, descCopy);
  467.               IF err = NoErr THEN err := OSARemoveStorageType(descCopy.dataHandle);
  468.               descCopy.descriptorType := MySignature; { internally we store as as type 'SMPL' }
  469.               resultingScriptID := 0; { we want a new OSAID }
  470.               err := FindSlotAndPutIt(globals, descCopy, resultingScriptID);
  471.               END;
  472.         DoOSALoad := err;
  473.       END;
  474.  
  475.     FUNCTION DoOSAStore(globals: GlobalsHandle;
  476.                         scriptID: OSAID;
  477.                         desiredType: DescType;
  478.                         modeFlags: LONGINT;
  479.                         VAR resultingScriptData: AEDesc): ComponentResult;
  480.     { make a copy of content in the slot and add trailer }
  481.  
  482.       VAR
  483.         err: ComponentResult;
  484.  
  485.       BEGIN
  486.         NukeIt(resultingScriptData);
  487.         IF (scriptID = 0) | (scriptID > MaxIDSlot) THEN
  488.           err := errOSAInvalidID
  489.         ELSE
  490.           BEGIN
  491.           resultingScriptData := globals^^.ScriptIDSlot[scriptID];
  492.           IF resultingScriptData.dataHandle = NIL THEN
  493.             err := errOSAInvalidID
  494.           ELSE
  495.             BEGIN
  496.             err := HandToHand(resultingScriptData.dataHandle);
  497.             IF err <> NoErr THEN NukeIt(resultingScriptData);
  498.             END;
  499.           IF err = NoErr THEN
  500.             BEGIN
  501.             err := OSAAddStorageType(resultingScriptData.dataHandle, resultingScriptData.descriptorType);
  502.             IF err = NoErr THEN
  503.               resultingScriptData.descriptorType := kOSAGenericScriptingComponentSubtype
  504.             ELSE
  505.               IgnoreOSErr(AEDisposeDesc(resultingScriptData));
  506.             END;
  507.           END;
  508.         DoOSAStore := err;
  509.       END;
  510.  
  511.     FUNCTION DoOSAScriptError(globals: GlobalsHandle;
  512.                               selector: OSType;
  513.                               desiredType: DescType;
  514.                               VAR resultingErrorDescription: AEDesc): ComponentResult;
  515.     { fetch the content of the error descriptor }
  516.  
  517.       VAR
  518.         err: ComponentResult;
  519.         i: longint;
  520.         aRec: AERecord;
  521.         myErrorDesc: AEDesc;
  522.         errNum: integer;
  523.  
  524.       BEGIN
  525.         NukeIt(resultingErrorDescription);
  526.         IF selector = kOSAErrorNumber THEN
  527.           BEGIN
  528.           errNum := globals^^.errorNumber;
  529.           err := AECoercePtr(typeShortInteger, @errNum, SizeOf(Integer), desiredType, resultingErrorDescription);
  530.           END
  531.         ELSE IF selector = kOSAErrorMessage THEN
  532.           BEGIN
  533.           myErrorDesc := globals^^.errorDesc;
  534.           IF (desiredType = typeChar) | (desiredType = typeWildCard) THEN
  535.             err := AEDuplicateDesc(myErrorDesc, resultingErrorDescription)
  536.           ELSE IF desiredType = 'STXT' THEN
  537.             err := TextToStxt(myErrorDesc, resultingErrorDescription)
  538.           ELSE
  539.             err := AECoerceDesc(myErrorDesc, desiredType, resultingErrorDescription);
  540.           END
  541.         ELSE IF selector = kOSAErrorRange THEN
  542.           BEGIN { in this simple example, we make the error range to include everything }
  543.           err := AECreateList(NIL, 0, true, aRec);
  544.           IF err = NoErr THEN
  545.             BEGIN
  546.             i := 0;
  547.             IgnoreOSErr(AEPutKeyPtr(aRec, keyOSASourceStart, typeLongInteger, @i, SizeOf(i)));
  548.             i := 30000;
  549.             IgnoreOSErr(AEPutKeyPtr(aRec, keyOSASourceEnd, typeLongInteger, @i, SizeOf(i)));
  550.             IF desiredType = typeAERecord THEN
  551.               resultingErrorDescription := aRec
  552.             ELSE
  553.               BEGIN
  554.               IF desiredType = typeWildCard THEN desiredType := typeOSAErrorRange;
  555.               err := AECoerceDesc(aRec, desiredType, resultingErrorDescription);
  556.               IgnoreOSErr(AEDisposeDesc(aRec));
  557.               END;
  558.             END;
  559.           END
  560.         ELSE
  561.           err := errOSABadSelector;
  562.         DoOSAScriptError := err;
  563.       END;
  564.  
  565.     FUNCTION DoOSADispose(globals: GlobalsHandle;
  566.                           scriptID: OSAID): ComponentResult;
  567.     { dispose the descriptor in the slot }
  568.  
  569.       BEGIN
  570.         IF (scriptID > 0) & (scriptID <= MaxIDSlot) THEN
  571.           BEGIN
  572.           HLock(Handle(globals));
  573.           IgnoreOSErr(AEDisposeDesc(globals^^.ScriptIDSlot[scriptID]));
  574.           HUnLock(Handle(globals));
  575.           END;
  576.         DoOSADispose := NoErr;
  577.       END;
  578.  
  579.     FUNCTION DoOSAExecute(globals: GlobalsHandle;
  580.                           compiledScriptID: OSAID;
  581.                           contextID: OSAID;
  582.                           modeFlags: LONGINT;
  583.                           VAR resultingScriptValueID: OSAID): ComponentResult;
  584.     { since in this sample program, internal form is the same as source form except for the descriptor type, we can just call CompileExecute }
  585.  
  586.       BEGIN
  587.         resultingScriptValueID := 0;
  588.         IF (compiledScriptID <= 0) | (compiledScriptID > MaxIDSlot) THEN
  589.           DoOSAExecute := errOSAInvalidID
  590.         ELSE
  591.           DoOSAExecute := DoOSACompileExecute(globals, globals^^.ScriptIDSlot[compiledScriptID], contextID, modeFlags, resultingScriptValueID);
  592.       END;
  593.  
  594.     FUNCTION DoOSADisplay(globals: GlobalsHandle;
  595.                           scriptValueID: OSAID;
  596.                           desiredType: DescType;
  597.                           modeFlags: LONGINT;
  598.                           VAR resultingText: AEDesc): ComponentResult;
  599.     { in this program, we have no special form for display so just coerce it }
  600.  
  601.       BEGIN
  602.         DoOSADisplay := DoOSACoerceToDesc(globals, scriptValueID, desiredType, modeFlags, resultingText);
  603.       END;
  604.  
  605.     FUNCTION DoOSACompile(globals: GlobalsHandle;
  606.                           sourceData: AEDesc;
  607.                           modeFlags: LONGINT;
  608.                           VAR resultingCompiledScriptID: OSAID): ComponentResult;
  609.     { since internal form is same as source, just change the dataType and call TryDoScript, if it compiles then just store it }
  610.  
  611.       VAR
  612.         err: ComponentResult;
  613.         descCopy, oldCopy: AEDesc;
  614.         num: integer;
  615.  
  616.       BEGIN
  617.         descCopy.dataHandle := NIL;
  618.         oldCopy.dataHandle := NIL;
  619.         IF sourceData.descriptorType = typeChar THEN
  620.           BEGIN
  621.           sourceData.descriptorType := MySignature;
  622.           err := TryDoScript(globals, sourceData, num);
  623.           IF err = NoErr THEN
  624.             BEGIN
  625.             err := AEDuplicateDesc(sourceData, descCopy);
  626.             IF err = NoErr THEN err := FindSlotAndPutIt(globals, descCopy, resultingCompiledScriptID);
  627.             END;
  628.           END
  629.         ELSE
  630.           err := errOSABadStorageType;
  631.         DoOSACompile := err;
  632.       END;
  633.  
  634.     FUNCTION DoOSAGetSource(globals: GlobalsHandle;
  635.                             scriptID: OSAID;
  636.                             desiredType: DescType;
  637.                             VAR resultingSourceData: AEDesc): ComponentResult;
  638.     { in this sample program, source is same as internal form and there is no special formatting, so just call coerce }
  639.  
  640.       BEGIN
  641.         DoOSAGetSource := DoOSACoerceToDesc(globals, scriptID, desiredType, 0, resultingSourceData);
  642.       END;
  643.  
  644.     FUNCTION DoOSACoerceFromDesc(globals: GlobalsHandle;
  645.                                  scriptData: AEDesc;
  646.                                  modeFlags: LONGINT;
  647.                                  VAR resultingScriptValueID: OSAID): ComponentResult;
  648.     { just store a copy into the slot }
  649.  
  650.       VAR
  651.         err: ComponentResult;
  652.         descCopy: AEDesc;
  653.  
  654.       BEGIN
  655.         err := NoErr;
  656.         descCopy.dataHandle := NIL;
  657.         err := AEDuplicateDesc(scriptData, descCopy);
  658.         IF err = NoErr THEN
  659.           BEGIN
  660.           resultingScriptValueID := 0; { put it in a new slot }
  661.           err := FindSlotAndPutIt(globals, descCopy, resultingScriptValueID);
  662.           END;
  663.         DoOSACoerceFromDesc := err;
  664.       END;
  665.  
  666.     FUNCTION DoOSACoerceToDesc(globals: GlobalsHandle;
  667.                                scriptValueID: OSAID;
  668.                                desiredType: DescType;
  669.                                modeFlags: LONGINT;
  670.                                VAR result: AEDesc): ComponentResult;
  671.     { fetch from the slot and coerce it, if it is source we rename the type because internal form is same as the source text }
  672.  
  673.       VAR
  674.         err: ComponentResult;
  675.         myScriptValue: AEDesc;
  676.  
  677.       BEGIN
  678.         IF (scriptValueID <= 0) | (scriptValueID > MaxIDSlot) THEN
  679.           err := errOSAInvalidID
  680.         ELSE
  681.           BEGIN
  682.           myScriptValue := globals^^.ScriptIDSlot[scriptValueID];
  683.           IF myScriptValue.descriptorType = MySignature THEN myScriptValue.descriptorType := typeChar;
  684.           IF myScriptValue.descriptorType = desiredType THEN
  685.             err := AEDuplicateDesc(myScriptValue, result)
  686.           ELSE IF desiredType = 'STXT' THEN
  687.             err := TextToStxt(myScriptValue, result)
  688.           ELSE
  689.             err := AECoerceDesc(myScriptValue, desiredType, result);
  690.           END;
  691.         DoOSACoerceToDesc := err;
  692.       END;
  693.  
  694.     FUNCTION DoOSALoadExecute(globals: GlobalsHandle;
  695.                               scriptData: AEDesc;
  696.                               contextID: OSAID;
  697.                               modeFlags: LONGINT;
  698.                               VAR resultingScriptValueID: OSAID): ComponentResult;
  699.     { strip the trailer, execute it and put back the trailer }
  700.     { there is chance we cannot restore the original form although we are try our best }
  701.     { this really calls for a GetScriptDataSize call in OSAComp }
  702.  
  703.       VAR
  704.         err: ComponentResult;
  705.         itsType: DescType;
  706.  
  707.       BEGIN
  708.         err := errOSABadStorageType;
  709.         IF (scriptData.descriptorType = kOSAGenericScriptingComponentSubtype) THEN
  710.           IF OSAGetStorageType(scriptData.dataHandle, itsType) = NoErr THEN
  711.             IF itsType = MySignature THEN
  712.               BEGIN
  713.               err := OSARemoveStorageType(scriptData.dataHandle);
  714.               IF err = NoErr THEN
  715.                 BEGIN
  716.                 err := DoOSACompileExecute(globals, scriptData, 0, 0, resultingScriptValueID);
  717.                 IF OSAAddStorageType(scriptData.dataHandle, MySignature) <> NoErr THEN
  718.                   BEGIN { we are in deep trouble, we change scriptData and cannot put it back }
  719.                   IgnoreOSErr(DoOSADispose(globals, resultingScriptValueID)); { dispose result to get back the memory }
  720.                   resultingScriptValueID := 0;
  721.                   IgnoreOSErr(OSAAddStorageType(scriptData.dataHandle, MySignature)); { now try again }
  722.                   err := memFullErr; { fail because we don't have enough memory }
  723.                   END;
  724.                 END;
  725.               END;
  726.         DoOSALoadExecute := err;
  727.       END;
  728.  
  729.     FUNCTION DoOSACompileExecute(globals: GlobalsHandle;
  730.                                  sourceData: AEDesc;
  731.                                  contextID: OSAID;
  732.                                  modeFlags: LONGINT;
  733.                                  VAR resultingScriptValueID: OSAID): ComponentResult;
  734.     { since source is same as internal form, just execute it and store the result }
  735.  
  736.       VAR
  737.         err: ComponentResult;
  738.         resultDesc: AEDesc;
  739.  
  740.       BEGIN
  741.         sourceData.descriptorType := MySignature;
  742.         err := ActualDoScript(globals, sourceData, resultDesc);
  743.         IF err = NoErr THEN err := FindSlotAndPutIt(globals, resultDesc, resultingScriptValueID);
  744.         DoOSACompileExecute := err;
  745.       END;
  746.  
  747.     FUNCTION DoOSADoScript(globals: GlobalsHandle;
  748.                            sourceData: AEDesc;
  749.                            contextID: OSAID;
  750.                            desiredType: DescType;
  751.                            modeFlags: LONGINT;
  752.                            VAR resultingText: AEDesc): ComponentResult;
  753.     { since source is same as internal form, just execute it and return the result }
  754.  
  755.       VAR
  756.         err: ComponentResult;
  757.         resultDesc: AEDesc;
  758.  
  759.       BEGIN
  760.         sourceData.descriptorType := MySignature;
  761.         NukeIt(resultingText);
  762.         err := ActualDoScript(globals, sourceData, resultDesc);
  763.         IF err = NoErr THEN
  764.           BEGIN
  765.           IF (desiredType = resultDesc.descriptorType) | (desiredType = typeWildCard) THEN
  766.             resultingText := resultDesc
  767.           ELSE
  768.             BEGIN
  769.             IF desiredType = 'STXT' THEN
  770.               err := TextToStxt(resultDesc, resultingText)
  771.             ELSE
  772.               err := AECoerceDesc(resultDesc, desiredType, resultingText);
  773.             IgnoreOSErr(AEDisposeDesc(resultDesc));
  774.             END;
  775.           END;
  776.         DoOSADoScript := err;
  777.       END;
  778.  
  779.     FUNCTION DoOSAMakeContext(contextName: StringPtr;
  780.                               parentContext: OSAID;
  781.                               VAR resultingContextID: OSAID): ComponentResult;
  782.     { context is not used in this sample program }
  783.  
  784.       BEGIN
  785.         resultingContextID := 0;
  786.         DoOSAMakeContext := NoErr;
  787.       END;
  788.  
  789.     FUNCTION DoOSAScriptingComponentName(globals: GlobalsHandle;
  790.                                          VAR resultingScriptingComponentName: AEDesc): OSAError;
  791.  
  792.       VAR
  793.         aStr: Str255;
  794.  
  795.       BEGIN
  796.         aStr := 'SampleScript';
  797.         DoOSAScriptingComponentName := AECreateDesc(typeChar, @aStr[1], length(aStr), resultingScriptingComponentName);
  798.       END;
  799.  
  800. END.
  801.